﻿using System;
using System.Collections.Generic;
using AudioStudio;
using GameFramework.Battle.Core;
using Gameplay.PVE.Utils;
using RootMotion.FinalIK;
using UnityEngine;
using Yoozoo.Libs;
using Yoozoo.Managers;

namespace Gameplay.PVE.Survivor
{
    public class SkillBase : BulletSpawner
    {
        protected enum ESkillState
        {
            None,
            Start,
            Storage,
            Cast,
            Recover,
        }

        private int id;
        private ESkillState state;
        public BattleUnit unit;
        public SkillConfig config;
        
        protected float stateStartTime;
        protected float skillStartTime;
        
        protected float storageTime;
        protected float recoverTime;
        protected float castTime;

        public float skillEndTime;
        
        private List<bool> bulletStateList = new List<bool>();
        private List<bool> effectStateList = new List<bool>();
        private List<bool> soundStateList = new List<bool>();
        private List<bool> skillEventStateList = new List<bool>();
        
        protected List<SkillTarget> bulletTargets = new List<SkillTarget>();

        private List<SkillBase> configChildSkills = new List<SkillBase>();
        private List<SkillBase> childSkills = new List<SkillBase>();
        
        public bool valid = true;

        protected ESearchChangeType searchChangeType;

        private float aimAngleSpeed = 0;
        //特殊瞄准，扫射
        private bool needAim = false;
        
        private int singleBulletEnergy = 0;
        private EBattleSkillSearchRandom randomType = EBattleSkillSearchRandom.None;
        private float bulletRetargetType = 0;
        private bool isFullBodyTrigger = false;
        protected virtual bool CanStorage()
        {
            return true;
        }

        protected virtual bool NeedStop()
        {
            return false;
        }
        
        protected virtual bool CanCast()
        {
            return TimeManager.time - stateStartTime >= storageTime;
        }
        
        protected virtual bool CanRecover()
        {
            return TimeManager.time - stateStartTime >= castTime;
        }
        
        protected virtual bool CanEnd()
        {
            return TimeManager.time - stateStartTime >= recoverTime;
        }

        public bool NeedSpecialAim()
        {
            return needAim;
        }

        //普通瞄准，即自动将枪口指向目标
        public bool NeedAim()
        {
            return config.follow_target == 0 && !needAim;
        }

        protected void SwitchState(ESkillState state)
        {
            this.state = state;
            stateStartTime = TimeManager.time;
        }

        protected virtual void StartStorage()
        {
            SwitchState(ESkillState.Storage);
            if (config.shape_type != 0)
            {
                if (config.shape_type < (int)EBulletShapeType.ShapeBottom)
                {
                    var forward = target.Position - unit.position;
                    var targetPos = new Vector3(target.position.x, target.position.y, target.position.z);
                    if (config.shape_type == (int)EBulletShapeType.Rect || config.shape_type == (int)EBulletShapeType.Sector)
                    {
                        targetPos = unit.position;
                    }
                    if (config.shape_fix != 0)
                    {
                        targetPos.Set(unit.position.x, unit.position.y, unit.position.z);
                        targetPos += (forward.normalized * config.shape_fix);
                    }

                    var sTime = config.shape_time;
                    Action<BattleGameObject> action = null;
                    if (needAim)
                    {
                        action = DirectorFollowAction;
                    }
                    //显示指示器
                    BattleEffectManager.Instance.ShowSkillDirector(
                        targetPos,
                        forward,
                        config.shape_time + config.shape_delay_time,
                        config.shape_type,
                        config.shape_params.ToArray(),
                        sTime,
                        action
                    );
                }
                else
                {
                    if (config.shape_type == (int)EBattleResId.SniperLine)
                    {
                        var effectId = config.shape_type;
                        var parent = unit.GetGunPoint((int)config.shape_params[0]);
                        var targetUnit = bulletTargets[0] != null && bulletTargets[0].unit != null ? bulletTargets[0].unit : this.target;
                        BattleEffectManager.Instance.CreateSniperLineEffect(effectId,parent,targetUnit.GetHitPoint(0),config.shape_time);
                    }
                }
            }

            if (!string.IsNullOrEmpty(config.storage_action_name))
            {
                unit.Play(config.storage_action_name);
            }
        }

        private void DirectorFollowAction(BattleGameObject gameObject)
        {
            var forward = unit.SpecialAimForward;
            forward.y = 0;
            gameObject.Forward = forward;
        }
        
        protected virtual void StartCast()
        {
            BeforeCast();
            OnStartCast();
            SwitchState(ESkillState.Cast);
        }

        protected virtual void OnStartCast()
        {
            var isfull = BattleConstValue.IsFullBodyTrigger(config.action_name);
            unit.Play(config.action_name, isfull);
            isFullBodyTrigger = isfull;
        }

        protected virtual void StartRecover()
        {
            SwitchState(ESkillState.Recover);
        }

        private void UpdateSound()
        {
            for (int i = 0; i < soundStateList.Count; i++)
            {
                if (!soundStateList[i])
                {
                    var frame = config.sound_frame[i].x;
                    var frameTime = frame / 30f;
                    if (TimeManager.time - skillStartTime >= frameTime)
                    {
                        if (config.sound_name.Count > i)
                        {
                            var soundId = config.sound_name[i];
                            if (config.sound_frame[i].y == 0)
                            {
                                AudioManager.PlaySound(soundId);
                            }
                            else
                            {
                                AudioManager.PlayVoice(soundId);
                            }
                        }
                        else
                        {
                            BattleDebug.LogError("技能声音配置错误 " + config.id + " sound_name找不到 " + i);
                        }
                        
                        soundStateList[i] = true;
                    }
                }
            }
        }

        private void UpdateSpecialEvents()
        {
            for (int i = 0; i < skillEventStateList.Count; i++)
            {
                if (!skillEventStateList[i])
                {
                    var frame = config.special_events[i].x;
                    var frameTime = frame / 30f;
                    if (TimeManager.time - skillStartTime >= frameTime)
                    {
                        var eventId = config.special_events[i].y;
                        var eventValue = config.special_events[i].z;
                        TriggerSpecialEvent((ESkillEventType)eventId, eventValue);
                        skillEventStateList[i] = true;
                    }
                }
            }
        }

        private void UpdateTargets()
        {
            for (int i = 0; i < bulletTargets.Count; i++)
            {
                var target = bulletTargets[i];
                if (!target.isValid)
                {
                    if (target.searchTargetTime >= 0 && TimeManager.time >= target.searchTargetTime)
                    {
                        FillTarget(target);
                    }
                }
            }
        }

        protected void TriggerSpecialEvent(ESkillEventType eventType, int eventValue)
        {
            if (eventType == ESkillEventType.HideWeapon)
            {
                unit.HideWeapon(eventValue);
            }
            else if (eventType == ESkillEventType.MoveSummonUnit)
            {
                unit.MoveSummonUnit(eventValue);
            }
            else if (eventType == ESkillEventType.SummonUnitCastSkill)
            {
                unit.SummonUnitCastSkill(eventValue);
            }
        }

        private bool isUpdateCast = false;
        private int gunPointEffectId = 0;
        private int gunPointIndex = 0;
        private Vector3 gunPointEffectStartPosition;
        private Vector3 gunPointEffectStartForward;

        protected virtual void UpdateStorage()
        {
            if ((config.follow_target == 2 || config.follow_target == 0) && !needAim && target != null)
            {
                unit.TargetForward = target.Position - unit.position;
            }
        }
        
        protected virtual void UpdateCast()
        {
            isUpdateCast = true;
            //准备子弹
            var time = TimeManager.time - stateStartTime;
            for (int i = 0; i < config.bullets.Count; i++)
            {
                if (!bulletStateList[i])
                {
                    var frame = config.bullets[i].x;
                    var frameTime = frame / 30f;
                    if (time >= frameTime)
                    {
                        var bulletId = config.bullets[i].y;
                        var pointIndex = config.bullets[i].z;
                        CastBullet((int)bulletId,pointIndex,i);
                        //检查是否有子子弹
                        var extraBulletId = unit.GetExtraBulletId(bulletId);
                        if (extraBulletId > 0)
                        {
                            CastBullet(extraBulletId,pointIndex,i);
                        }

                        if (singleBulletEnergy > 0)
                        {
                            unit.SetMpChange(singleBulletEnergy);
                        }
                        bulletStateList[i] = true;
                    }
                }
            }

            CheckNeedChangeTarget();
            if (NeedAim())
            {
                if (target != null && !target.isDead && !unit.isManualMoving)
                {
                    unit.TargetForward = target.Position - unit.position;
                }
            }
        }

        protected void CheckNeedChangeTarget()
        {
            if (searchChangeType == ESearchChangeType.OnTargetDead)
            {
                if (target == null || target.isDead)
                {
                    var newTarget = SearchTargetHelper.GetSkillTarget(unit, this);
                    if (newTarget != null)
                    {
                        SetTarget(newTarget);
                        for (int i = 0; i < bulletTargets.Count; i++)
                        {
                            var target = bulletTargets[i];
                            target.Clear();
                            FillTarget(target,true);
                        }
                    }
                }
            }
        }
        
        protected void OnSetTarget()
        {
            if (needAim)
            {
                unit.StartSpecialAim(target.AimPoint,aimAngleSpeed);
            }
        }

        public virtual void LateUpdate()
        {
            for (int i = 0; i < childSkills.Count; i++)
            {
                childSkills[i].LateUpdate();
            }
            if (gunPointEffectId > 0)
            {
                var point = unit.GetGunPoint(gunPointIndex);
                BattleEffectManager.Instance.CreateEffectAutoDispose(gunPointEffectId,point.position,point.forward,1,point);
                gunPointEffectId = 0;
            }
            if (!isUpdateCast)
            {
                return;
            }
            isUpdateCast = false;
            var time = TimeManager.time - stateStartTime;
            for (int i = 0; i < config.effects.Count; i++)
            {
                if (!effectStateList[i])
                {
                    var frame = config.effects[i].x;
                    var frameTime = frame / 30f;
                    if (time >= frameTime)
                    {
                        var effectId = config.effects[i].y;
                        var targetForward = unit.Forward;
                        if (unit.isAiming && NeedAim())
                        {
                            targetForward = unit.AimForward;
                        }
                        var effectParent = unit.GetGunPoint(config.effects[i].z);
                        BattleEffectManager.Instance.CreateEffectAutoDispose(effectId,unit.Position,targetForward,2,effectParent);
                        effectStateList[i] = true;
                    }
                }
            }
        }

        protected virtual void CastBullet(int bulletId,int pointIndex,int bulletIndex)
        {
            bulletId = unit.GetBulletId(bulletId);
            var config = BattleConfigManager.Instance.GetBulletConfig(bulletId);
            if (config == null)
            {
                BattleDebug.LogError("子弹找不到 " + bulletId);
                return;
            }
            var bullet = BulletManager.Instance.CreateBullet(config);
            bullet.pointIndex = pointIndex;
            var target = bulletTargets[bulletIndex];
            if (target.searchTargetTime < 0)
            {
                FillTarget(target);
            }
            bullet.SetTarget(target);
            bullet.Initialize(config,this,unit);
            var startPosition = GetBulletStartPosition(pointIndex);
            var startForward = GetBulletStartForward(bulletIndex);
            bullet.SetStartPosition(startPosition);
            bullet.Start();
            //播放枪口动画
            if (config.create_effect_id > 0)
            {
                gunPointIndex = pointIndex;
                gunPointEffectId = config.create_effect_id;
                gunPointEffectStartPosition = startPosition;
                gunPointEffectStartForward = startForward;
            }
        }

        protected virtual Vector3 GetBulletStartPosition(int pointIndex = 0)
        {
            return unit.GetGunPoint(pointIndex).position;
        }

        protected virtual Vector3 GetBulletStartForward(int bulletIndex)
        {
            var target = bulletTargets[bulletIndex];
            if (target.isValid)
            {
                return target.GetTargetForward();
            }
            return unit.Forward;
        }

        protected virtual Transform GetBulletCreateEffectParent()
        {
            return null;
        }

        protected virtual void OnEnd()
        {
            
        }
        
        public void End()
        {
            if (state == ESkillState.None)
            {
                return;
            }
            OnEnd();
            state = ESkillState.None;
            skillEndTime = TimeManager.time;
            justEnd = true;
            if (needAim)
            {
                unit.EndSpecialAim();
            }
            if (isFullBodyTrigger)
            {
                isFullBodyTrigger = false;
                unit.Play("Born");
            }
            else if (unit.team == 2)
            {
                unit.Play("Idle");
            }
        }
        
        public void Update()
        {
            var currentTime = TimeManager.time;
            if (state == ESkillState.Start)
            {
                if (CanStorage())
                {
                    StartStorage();
                }
            }

            if (NeedStop())
            {
                End();
                return;
            }
            if (state == ESkillState.Storage)
            {
                if (CanCast())
                {
                    StartCast();
                }
                else
                {
                    UpdateStorage();
                }
            }
            else if (state == ESkillState.Cast)
            {
                UpdateCast();
                if (CanRecover())
                {
                    StartRecover();
                }
                
            }
            else if (state == ESkillState.Recover)
            {
                if (CanEnd())
                {
                    End();
                }
            }

            if (state != ESkillState.None)
            {
                UpdateSound();
                UpdateSpecialEvents();
                UpdateTargets();
            }

            for (int i = 0; i < childSkills.Count; i++)
            {
                childSkills[i].Update();
            }
        }

        public void Initialize(SkillConfig config, BattleUnit unit)
        {
            this.config = config;
            this.unit = unit;
            searchChangeType = (ESearchChangeType)config.search_change_type;
            if (searchChangeType != ESearchChangeType.Default)
            {
                aimAngleSpeed = config.GetParam("AimAngleSpeed");
                needAim = config.GetParam("Aim") == 1f;
            }

            randomType = (EBattleSkillSearchRandom)config.GetParam("RandomType");
            bulletRetargetType = config.GetParam("Retarget");
            searchSort = (EBattleSkillSearchSort)config.search_sort;
            storageTime = config.storage_time;
            recoverTime = config.recover_time;
            castTime = config.cast_time;
            bulletStateList.Clear();
            for (int i = 0; i < config.bullets.Count; i++)
            {
                bulletStateList.Add(false);
            }
            effectStateList.Clear();
            for (int i = 0; i < config.effects.Count; i++)
            {
                effectStateList.Add(false);
            }
            soundStateList.Clear();
            for (int i = 0; i < config.sound_frame.Count; i++)
            {
                soundStateList.Add(false);
            }
            skillEventStateList.Clear();
            for (int i = 0; i < config.special_events.Count; i++)
            {
                skillEventStateList.Add(false);
            }
            RemoveBulletTargets();
            if (config.bullets.Count > 0)
            {
                singleBulletEnergy = config.add_energy / config.bullets.Count;
            }
            else
            {
                singleBulletEnergy = 0;
            }
            for (int i = 0; i < config.bullets.Count; i++)
            {
                var bulletConfig = BattleConfigManager.Instance.GetBulletConfig(config.bullets[i].y);
                var bulletTarget = ClassManager.Get<SkillTarget>();
                if (bulletConfig.move_type == (int)EBulletMovementType.Track)
                {
                    bulletTarget.targetType = ESkillTargetType.Unit;
                }
                else// if (bulletConfig.move_type == (int)EBulletMovementType.Parabola || bulletConfig.move_type == (int)EBulletMovementType.Stick)
                {
                    bulletTarget.targetType = ESkillTargetType.Position;
                }
                /*else
                {
                    bulletTarget.targetType = ESkillTargetType.Forward;
                }*/
                bulletTarget.bulletConfig = bulletConfig;
                bulletTarget.advancedFrame = bulletConfig.locktarget_advframe;
                bulletTarget.bulletStartFrame = config.bullets[i].x;
                bulletTarget.source = unit;
                bulletTargets.Add(bulletTarget);
            }
            configChildSkills.Clear();
            //判断子技能
            if (config.child_skills != null)
            {
                for (int i = 0; i < config.child_skills.Count; i++)
                {
                    var childSkill = ClassManager.Get<PassiveSkill>();
                    var childSkillConfig = BattleConfigManager.Instance.GetSkillConfig(config.child_skills[i]);
                    childSkill.Initialize(childSkillConfig,unit);
                    configChildSkills.Add(childSkill);
                }
            }
        }

        protected virtual SkillBase GetExtraSkill()
        {
            return unit.GetExtraChildSkill(config.id);
        }
        
        public void Start(bool isChild = false)
        {
            this.startTime = TimeManager.time;
            childSkills.Clear();
            childSkills.AddRange(configChildSkills);
            var extraSkill = GetExtraSkill();
            if (extraSkill != null)
            {
                //BattleDebug.LogError("获得了子技能 " + extraSkill.config.id);
                childSkills.Add(extraSkill);
            }
            
            skillStartTime = TimeManager.time;
            if (!isChild)
            {
                StatisticManager.Instance.AddTimes(unit,damageType);
            }
            SwitchState(ESkillState.Start);
            AutoSearch();
            OnStart();
            for (int i = 0; i < childSkills.Count; i++)
            {
                var target = SearchTargetHelper.GetSkillTarget(unit, childSkills[i]);
                if (target != null)
                {
                    //BattleDebug.LogError("子技能" + childSkills[i].config.id + "目标" + target.unitId);
                    childSkills[i].SetTarget(target);
                }
                childSkills[i].Start(true);
            }
        }

        protected virtual void OnStart()
        {
            
        }

        public bool IsInSkill()
        {
            return state != ESkillState.None;
        }

        protected BattleUnit target;
        
        public void SetTarget(BattleUnit target)
        {
            this.target = target;
            OnSetTarget();
        }

        private bool justEnd;

        public bool JustEnd()
        {
            return justEnd;
        }

        public void Reset()
        {
            justEnd = false;
        }

        public override int GetTargetTeam()
        {
            var result = 0;
            if (config.search_type == 0)
            {
                result = result | BattleHelper.GetTeamMask(unit.team, true);
            }
            else if (config.search_type == 1)
            {
                result = result | BattleHelper.GetTeamMask(unit.team);
            }
            else if (config.search_type == -1)
            {
                result = BattleHelper.GetTeamMaskByEnum(ETargetTeam.All);
            }
            return result;
        }

        private void BeforeCast()
        {
            for (int i = 0; i < bulletStateList.Count; i++)
            {
                bulletStateList[i] = false;
            }
            for (int i = 0; i < effectStateList.Count; i++)
            {
                effectStateList[i] = false;
            }

            for (int i = 0; i < soundStateList.Count; i++)
            {
                soundStateList[i] = false;
            }

            for (int i = 0; i < skillEventStateList.Count; i++)
            {
                skillEventStateList[i] = false;
            }
            randomTarget = null;
        }

        protected void AutoSearch()
        {
            for (int i = 0; i < bulletTargets.Count; i++)
            {
                var target = bulletTargets[i];
                target.Clear();
                if (target.advancedFrame == 0)
                {
                    FillTarget(target);
                }
                else if (target.advancedFrame > 0)
                {
                    var advancedTime = (target.bulletStartFrame - target.advancedFrame) / 30f;
                    advancedTime = Mathf.Max(advancedTime, 0);
                    target.searchTargetTime = skillStartTime + advancedTime;
                }
                else
                {
                    target.searchTargetTime = -1;
                }
            }
        }
        
        private BattleUnit randomTarget;
        protected virtual void FillTarget(SkillTarget target,bool useParent = false)
        {
            if (searchSort == EBattleSkillSearchSort.Random)
            {
                if (randomType == EBattleSkillSearchRandom.TragetRange)
                {
                    if (randomTarget == null)
                    {
                        randomTarget = SearchTargetHelper.GetSkillTarget(unit, this,true);
                    }

                    if (randomTarget == null)
                    {
                        target.isValid = false;
                        return;
                    }
                    if (target.targetType == ESkillTargetType.Unit)
                    {
                        if (useParent)
                        {
                            target.unit = this.target;
                        }
                        else
                        {
                            target.unit = UnitManager.Instance.SearchTarget(randomTarget, this.GetTargetTeam(),
                                (EBattleSkillSearchSort)config.search_sort, 9999);
                        }
                        target.isValid = target.unit != null;
                    }
                    else if (target.targetType == ESkillTargetType.Position)
                    {
                        BattleUnit t = null;
                        target.position = SearchTargetHelper.GetSkillTargetPosition(randomTarget, this,ref t,true);
                        target.unit = t;
                        target.isValid = true;
                    }

                    target.OnGetTarget();
                    return;
                }
            }
            if (target.targetType == ESkillTargetType.Unit)
            {
                if (useParent)
                {
                    target.unit = this.target;
                }
                else
                {
                    target.unit = SearchTargetHelper.GetSkillTarget(unit, this,true);
                }
                target.isValid = target.unit != null;
            }
            else if (target.targetType == ESkillTargetType.Position)
            {
                BattleUnit t = null;
                target.position = SearchTargetHelper.GetSkillTargetPosition(unit, this,ref t,true);
                target.unit = t;
                target.isValid = true;
            }

            target.OnGetTarget();
        }

        private void RemoveBulletTargets()
        {
            for (int i = 0; i < bulletTargets.Count; i++)
            {
                ClassManager.Free(bulletTargets[i]);
            }
            bulletTargets.Clear();
        }
        
        public override void OnReset()
        {
            base.OnReset();
            for (int i = 0; i < childSkills.Count; i++)
            {
                ClassManager.Free(childSkills[i]);
            }
            childSkills.Clear();
            RemoveBulletTargets();
            target = null;
            justEnd = false;
            unit = null;
            config = null;
            state = ESkillState.None;
            stateStartTime = 0;
            skillStartTime = 0;
            skillEndTime = 0;
            storageTime = 0;
            recoverTime = 0;
            castTime = 0;
            bulletStateList.Clear();
            effectStateList.Clear();
            soundStateList.Clear();
            skillEventStateList.Clear();
        }
    }
}
